package com.ruyuan.seckilling.inventory.service.impl;

import com.alibaba.fastjson.JSON;
import com.ruyuan.seckilling.common.CacheKey;
import com.ruyuan.seckilling.common.LuaScript;
import com.ruyuan.seckilling.inventory.service.InventoryService;
import com.ruyuan.seckilling.inventory.vo.ProductStockVo;
import com.ruyuan.starter.jedis.CacheSupport;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;

/**
 * @author zhonghuashishan
 */
@Slf4j
@Service
public class InventoryServiceImpl implements InventoryService {

    @Autowired
    private CacheSupport cacheSupport;

    @Override
    public ProductStockVo queryCurrentStock(Long activityId, Long skuId) {

        List<Map<String, String>> stockList = cacheSupport.hgetAllOnAllRedis(CacheKey.buildStockKey(activityId, skuId));

        int salableStock = 0;
        int lockedStock = 0;
        int saledStock = 0;
        for (Map<String, String> stockMap : stockList) {
            salableStock += Integer.parseInt(stockMap.get(CacheKey.SALABLE_STOCK));
            lockedStock += Integer.parseInt(stockMap.get(CacheKey.LOCKED_STOCK));
            saledStock += Integer.parseInt(stockMap.get(CacheKey.SALED_STOCK));
        }

        return ProductStockVo.builder().activityId(activityId).skuId(skuId).salableStock(salableStock)
                .lockedStock(lockedStock).saledStock(saledStock).build();
    }

    @Override
    public Boolean syncStock(Long activityId, Long skuId, Integer stock) {

        // 这种方式分片测试时发现一个问题
        // 比如，现在库存是10，redis的个数是6
        // 按照下面方式，最后的结果是：1、1、1、1、1、5
        // 但是我们希望的是尽可能均分：2、2、2、2、1、1
        // int redisCount = cacheSupport.getRedisCount();
        // int stockPerRedis = stock / redisCount;
        // int stockLastRedis = stock - (stockPerRedis * (redisCount - 1));

        // 所以现在我们改成这样分片
        int redisCount = cacheSupport.getRedisCount();
        // key是redis的索引，value是redis上应该分的库存
        Map<Integer, Integer> map = new HashMap<>();
        for (int i = 0; i < stock; i++) {
            int index = i % redisCount;
            map.putIfAbsent(index, 0);
            map.put(index, map.get(index) + 1);
        }

        List<Map<String, String>> stockList = new ArrayList<>();
        for (int i = 0; i < redisCount; i++) {
            Map<String, String> stockMap = new HashMap<>();
            stockMap.put(CacheKey.SALABLE_STOCK, map.get(i) + "");
            stockMap.put(CacheKey.LOCKED_STOCK, "0");
            stockMap.put(CacheKey.SALED_STOCK, "0");
            stockList.add(stockMap);
            log.info("库存分片 stockMap={}", JSON.toJSONString(stockMap));
        }

        cacheSupport.hsetOnAllRedis(CacheKey.buildStockKey(activityId, skuId), stockList);

        return Boolean.TRUE;
    }

    @Override
    public Boolean confirmStock(Long sequence, Long activityId, Long skuId) {
        String stockKey = CacheKey.buildStockKey(activityId, skuId);
        String script = LuaScript.buildConfirmStockScript(stockKey);
        cacheSupport.eval(sequence, script);
        return Boolean.TRUE;
    }

    @Override
    public Boolean releaseStock(Long sequence, Long activityId, Long skuId) {
        String stockKey = CacheKey.buildStockKey(activityId, skuId);
        String script = LuaScript.buildReleaseStockScript(stockKey);
        cacheSupport.eval(sequence, script);
        return Boolean.TRUE;
    }

    @Override
    public Boolean cleanStock(Long activityId, Long skuId) {
        cacheSupport.delOnAllRedis(CacheKey.buildStockKey(activityId, skuId));
        return Boolean.TRUE;
    }
}
